package com.dlkw.easyroom.compiler;

import androidx.room.DatabaseView;
import androidx.room.Entity;

import com.squareup.javapoet.JavaFile;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

public class Tools {
    private static ProcessingEnvironment environment;
    private static Types typeUtils;
    private static Elements elementUtils;

    public static void init(ProcessingEnvironment processingEnvironment) {
        environment = processingEnvironment;
        typeUtils = processingEnvironment.getTypeUtils();
        elementUtils = processingEnvironment.getElementUtils();
    }

    public static void log(String msg) {
        log(Diagnostic.Kind.NOTE, msg);
    }

    public static void log(Diagnostic.Kind kind, String msg) {
        msg = "EasyRoomLog:" + msg;
        environment.getMessager().printMessage(kind, msg);
    }

    public static void writeToFiler(JavaFile javaFile) throws IOException {
        javaFile.writeTo(environment.getFiler());
    }

    public static TypeElement getTypeElement(String name) {
        return environment.getElementUtils().getTypeElement(name);
    }

    public static String getTableName(TypeElement typeElement) {
        Entity entity = typeElement.getAnnotation(Entity.class);
        if (null == entity || null == entity.tableName() || entity.tableName().isEmpty()) {
            return typeElement.getSimpleName().toString();
        }
        return entity.tableName();
    }

    public static String getViewName(TypeElement element) {
        DatabaseView view = element.getAnnotation(DatabaseView.class);
        return null == view ? element.getSimpleName().toString() : view.viewName();
    }

    public static boolean isImplementingBaseDao(TypeElement typeElement) {
        TypeElement baseDao = elementUtils.getTypeElement("com.dlkw.easyroom.BaseDao");
        if (baseDao == null) {
            // BaseDao 接口未找到
            return false;
        }

        TypeMirror baseDaoType = baseDao.asType();

        // 检查当前类是否直接或间接实现 BaseDao
        for (TypeMirror type : typeUtils.directSupertypes(typeElement.asType())) {
            if (isTypeOrSuperTypeImplementing(type, baseDaoType)) {
                return true;
            }
        }

        return false;
    }

    public static boolean isTypeOrSuperTypeImplementing(TypeMirror type, TypeMirror baseDaoType) {
        if (typeUtils.isAssignable(type, baseDaoType)) {
            return true;
        }

        // 只处理声明过的类型（类、接口）
        if (type instanceof DeclaredType) {
            for (TypeMirror superType : typeUtils.directSupertypes(type)) {
                if (isTypeOrSuperTypeImplementing(superType, baseDaoType)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 获取指定 Dao 接口实现的 BaseDao<T> 中的 T 类型
     */
    public static TypeMirror resolveEntityType(TypeElement daoInterface, String baseDaoQualifiedName) {
        // 获取 BaseDao<T> 接口
        TypeElement baseDaoTypeElement = elementUtils.getTypeElement(baseDaoQualifiedName);
        if (baseDaoTypeElement == null) {
            throw new IllegalArgumentException("BaseDao not found: " + baseDaoQualifiedName);
        }

        // 遍历当前接口实现的所有父接口/类
        for (TypeMirror superType : typeUtils.directSupertypes(daoInterface.asType())) {
            if (superType instanceof DeclaredType) {
                DeclaredType declaredType = (DeclaredType) superType;
                TypeElement superTypeElement = (TypeElement) typeUtils.asElement(superType);

                if (superTypeElement.getQualifiedName().contentEquals(baseDaoQualifiedName)) {
                    List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
                    if (!typeArguments.isEmpty()) {
                        return typeArguments.get(0); // 返回 T
                    }
                } else {
                    // 递归检查父接口是否继承了 BaseDao<T>
                    TypeMirror result = resolveEntityType(superTypeElement, baseDaoQualifiedName);
                    if (result != null) {
                        return result;
                    }
                }
            }
        }

        return null;
    }

    public static List<VariableElement> getFields(TypeElement ele) {
        return elementUtils.getAllMembers(ele)
                .stream()
                .filter(VariableElement.class::isInstance)
                .map(VariableElement.class::cast)
                .collect(Collectors.toList());
    }
}
